package com.changgou.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fescar.spring.annotation.GlobalTransactional;
import com.changgou.goods.feign.SkuFeign;
import com.changgou.order.config.RabbitMQConfig;
import com.changgou.order.dao.*;
import com.changgou.order.pojo.*;
import com.changgou.order.service.CartService;
import com.changgou.order.service.OrderService;
import com.changgou.pay.feign.WxPayFeign;
import com.changgou.util.IdWorker;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.time.LocalDate;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderMapper orderMapper;

    /**
     * 查询全部列表
     * @return
     */
    @Override
    public List<Order> findAll() {
        return orderMapper.selectAll();
    }

    /**
     * 根据ID查询
     * @param id
     * @return
     */
    @Override
    public Order findById(String id){
        return  orderMapper.selectByPrimaryKey(id);
    }

    @Autowired
    private CartService cartService;

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private OrderItemMapper orderItemMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private SkuFeign skuFeign;

    @Autowired
    private TaskMapper taskMapper;

    @Autowired
    private RabbitTemplate rabbitTemplate;
    /**
     * 新增Order
     *
     *      前端传递过来的字段:
     *          payType
     *          receiveContact
     *          receiveAddress
     *          receiveMobile
     *      其他字段需要手动设置
     *
     * 业务逻辑: 保存 order(订单)数据和orderItem(订单项/订单明细)数据
     *      查询出购物车数据,总金额,总数量,购物车列表
     *      将它们封装order和orderItem中
     *      删除redis中的购物车列表数据
     *
     * @param order
     */
    @Override
    @GlobalTransactional(name = "order_add")
    public String add(Order order){
        //TODO 1 新增订单和订单项数据,并扣减库存
        //changgou_order的tb_order表
        //获取购物车相关数据,总金额,总数量,购物车列表
        Map<String, Object> cartMap = cartService.list(order.getUsername());
        Integer totalNum = (Integer) cartMap.get("totalNum");
        Integer totalPrice = (Integer) cartMap.get("totalPrice");

        //封装订单数据
        order.setId(idWorker.nextId()+"");

        order.setTotalNum(totalNum);//总数量
        order.setTotalMoney(totalPrice);//总金额
        order.setPayMoney(totalPrice);//支付金额

        order.setCreateTime(new Date());
        order.setUpdateTime(order.getCreateTime());

        order.setBuyerRate("0");//0未评价,1已评价
        order.setOrderStatus("0");//0未完成,1已完成
        order.setPayStatus("0");//0未付款,1已付款,2支付失败
        order.setConsignStatus("0");//0未发货,1已发货,2已收货
        order.setSourceType("1");//1.web页面

        orderMapper.insert(order);

        //封装订单项明细,orderItem
        List<OrderItem> orderItemList = (List<OrderItem>) cartMap.get("orderItemList");
        for (OrderItem orderItem : orderItemList) {
            orderItem.setId(idWorker.nextId()+"");
            orderItem.setOrderId(order.getId());
            orderItem.setIsReturn("0");//未退货
            orderItemMapper.insertSelective(orderItem);
        }

        //changgou_user的tb_user
        //扣减库存
        skuFeign.decrCount(order.getUsername());

//        int i=1/0;//异常模拟

        //新增积分,通过feign进行调用,tb_user的points字段
        //TODO 2 向任务类中插入一条记录
        Task task = new Task();
        task.setCreateTime(new Date());
        task.setUpdateTime(new Date());
        task.setMqExchange(RabbitMQConfig.EX_BUYING_ADDPOINTUSER);
        task.setMqRoutingkey(RabbitMQConfig.CG_BUYING_ADDPOINT_KEY);

        //将请求体中的参数添加到tb_point_log,userId(username),orderId,point(和支付金额是一比一)
        Map map = new HashMap();
        map.put("username",order.getUsername());
        map.put("orderId",order.getId());
        map.put("point",order.getPayMoney());
        task.setRequestBody(JSON.toJSONString(map));

        //将任务类插入到数据库中
        taskMapper.insertSelective(task);

        //删除redis中数据,Cart_username,根据大Key删除整个集合
        redisTemplate.delete("Cart_"+order.getUsername());

        // TODO 发送消息,如果订单超时,关闭订单
        rabbitTemplate.convertAndSend("",RabbitMQConfig.QUEUE_ORDER_CREATE,order.getId());

        //返回订单ID
        return order.getId();
    }


    /**
     * 修改
     * @param order
     */
    @Override
    public void update(Order order){
        orderMapper.updateByPrimaryKey(order);
    }

    /**
     * 删除
     * @param id
     */
    @Override
    public void delete(String id){
        orderMapper.deleteByPrimaryKey(id);
    }


    /**
     * 条件查询
     * @param searchMap
     * @return
     */
    @Override
    public List<Order> findList(Map<String, Object> searchMap){
        Example example = createExample(searchMap);
        return orderMapper.selectByExample(example);
    }

    /**
     * 分页查询
     * @param page
     * @param size
     * @return
     */
    @Override
    public Page<Order> findPage(int page, int size){
        PageHelper.startPage(page,size);
        return (Page<Order>)orderMapper.selectAll();
    }

    /**
     * 条件+分页查询
     * @param searchMap 查询条件
     * @param page 页码
     * @param size 页大小
     * @return 分页结果
     */
    @Override
    public Page<Order> findPage(Map<String,Object> searchMap, int page, int size){
        PageHelper.startPage(page,size);
        Example example = createExample(searchMap);
        return (Page<Order>)orderMapper.selectByExample(example);
    }

    @Autowired
    private OrderLogMapper orderLogMapper;
    @Override
    public void updatePayStatus(String out_trade_no, String transaction_id) {
        Order order = orderMapper.selectByPrimaryKey(out_trade_no);
        //在更改订单状态之前,未支付的状态
        if(order != null && order.getPayStatus().equals("0")){
            order.setPayStatus("1");//已支付
            order.setOrderStatus("1");
            order.setUpdateTime(new Date());
            order.setPayTime(new Date());
            order.setTransactionId(transaction_id);
            orderMapper.updateByPrimaryKeySelective(order);

            //插入一条订单日志
            OrderLog orderLog = new OrderLog();
            orderLog.setId(idWorker.nextId()+"");
            orderLog.setOperater("system");//系统操作
            orderLog.setOperateTime(new Date());
            orderLog.setOrderId(order.getId());
            orderLog.setPayStatus("1");
            orderLog.setOrderStatus("1");
            orderLog.setRemarks("交易流水号"+transaction_id);
            orderLogMapper.insertSelective(orderLog);
        }
    }

    @Autowired
    private WxPayFeign wxPayFeign;
    /**
     * 关闭订单操作
     * @param orderId
     */
    @Override
    @Transactional
    public void closeOrder(String orderId) {
        //查询订单
        Order order = orderMapper.selectByPrimaryKey(orderId);

        if(order == null ){
            throw new RuntimeException("订单不存在!");
        }

        if(!"0".equals(order.getOrderStatus())){
            throw new RuntimeException("该订单无需关闭");
        }

        //查询支付状态
        Map queryOrderMap = (Map) wxPayFeign.queryOrder(orderId).getData();

        if("SUCCESS".equals(queryOrderMap.get("trade_state"))) {
            //已支付,补偿消息,更新订单为已支付的状态
            updatePayStatus(orderId , (String) queryOrderMap.get("transaction_id"));
        }

        if("NOTPAY".equals(queryOrderMap.get("trade_state"))){
            //记录日志和回滚库存
            order.setCloseTime(new Date());
            order.setOrderStatus("4");//4 订单已关闭
            orderMapper.updateByPrimaryKeySelective(order);

            OrderLog orderLog = new OrderLog();
            orderLog.setId(idWorker.nextId()+"");
            orderLog.setOrderStatus("4");
            orderLog.setOperateTime(new Date());
            orderLog.setOperater("system");
            orderLog.setOrderId(orderId);
            orderLogMapper.insertSelective(orderLog);

            //回滚库存
            OrderItem oi = new OrderItem();
            oi.setOrderId(orderId);
            List<OrderItem> orderItemList = orderItemMapper.select(oi);

            for (OrderItem orderItem : orderItemList) {
                skuFeign.resumeStockNum(orderItem.getSkuId(),orderItem.getNum());
            }

            //未支付,关闭订单
            wxPayFeign.closeOrder(orderId);
        }

    }

    /**
     * 传递的参数,数据库必须有该订单
     *      [
     *          {
     *              "id":"xxx",
     *              "shippingName":"顺丰快递",
     *              "shippingCode":"123klj12l3kj123",
     *              "consignStatus":"0",
     *              "orderStatus":"1"
     *          },
     *          {...}...
     *      ]
     * @param orders
     */
    @Override
    @Transactional
    public void batchSend(List<Order> orders) {
        //可以写在一个for循环里面,比如,第100条出现了异常,回滚前99条.
        //可以通过for循环去进行三次校验,校验通过了,最后插入就没问题.
        for (Order order : orders) {
            //判断是否有物流公司和运单号吗
            if(order.getShippingName() == null || order.getShippingCode() == null){
                throw new RuntimeException("订单号码异常");
            }
        }

        // orderStatus 订单状态
        // 0 未支付状态 1 已支付,未发货 2 已支付,已发货 3 已收货,已完成 4 已关闭
        // consignStatus 发货状态
        // 0 未发货 1已发货 2 已送达
        // 校验订单状态
        for (Order order : orders) {
            //根据id查询出order信息
            Order o = orderMapper.selectByPrimaryKey(order.getId());
            if( !"1".equals(o.getOrderStatus()) || !"0".equals(o.getConsignStatus()) ){
                //已发货或未支付的其他状态,抛出异常
                throw new RuntimeException("订单状态有误!");
            }
        }

        //循环批量发货
        for (Order order : orders) {
            //更新order的状态
            order.setOrderStatus("2");
            order.setConsignStatus("1");
            order.setConsignTime(new Date());
            order.setUpdateTime(new Date());
            //插入到数据库中
            orderMapper.updateByPrimaryKeySelective(order);

            //记录order日志
            OrderLog orderLog = new OrderLog();
            orderLog.setId(idWorker.nextId()+"");
            orderLog.setOperater("system");
            orderLog.setOperateTime(new Date());
            orderLog.setOrderStatus("2");
            orderLog.setConsignStatus("1");
            orderLogMapper.insertSelective(orderLog);
        }

    }

    /**
     * 用户确认收货
     * @param orderId 订单ID
     * @param operator 操作者(用户user/username , 系统system , 管理员admin)
     */
    @Override
    public void confirmTake(String orderId, String operator) {
        //基本校验
        Order order = orderMapper.selectByPrimaryKey(orderId);
        if(order == null){
            throw new RuntimeException("订单不存在.");
        }

        if("0".equals(order.getConsignStatus())){
            //未发货状态
            throw new RuntimeException("订单未发货!");
        }
        //修改订单的参数
        // orderStatus 订单状态
        // 0 未支付状态 1 已支付,未发货 2 已支付,已发货 3 已收货,已完成 4 已关闭
        // consignStatus 发货状态
        // 0 未发货 1已发货 2 已送达,已收货
        order.setOrderStatus("3");
        order.setConsignStatus("2");
        order.setConsignTime(new Date());
        order.setEndTime(new Date());//结束交易的时间

        //记录订单日志
        OrderLog orderLog = new OrderLog();
        orderLog.setId(idWorker.nextId()+"");
        orderLog.setConsignStatus("2");
        orderLog.setOperateTime(new Date());
        orderLog.setOrderStatus("3");
        orderLog.setOperater(operator);//系统 管理员 用户,如果是用户点击的确认收货,user,如果是自动收货system
        orderLog.setOrderId(orderId);
        orderLogMapper.insertSelective(orderLog);
    }

    @Autowired
    private OrderConfigMapper orderConfigMapper;

    /**
     * 自动确认收货
     *      查询出距离当前时间15天之前的订单,修改状态,自动确认收货.
     */
    @Override
    public void orderAutoTake() {
        //从数据库查询,自动确认收货的期限
        //过期时间配置
        OrderConfig orderConfig = orderConfigMapper.selectByPrimaryKey(1);

        //计算出当前的订单的过期时间
        LocalDate now = LocalDate.now();
        //查询当前日期的15天前的数据,需要把它自动收货
        //当前日期,4月29日.之前的15天的订单需要自动确认收货.
        LocalDate localDate = now.plusDays(-orderConfig.getTakeTimeout());// -15
        System.out.println(localDate);

        //条件查询,已发货未收的订单状态,2
        //select * from tb_order where order_status=2 and consign_status=1 and consign_time <= localDate
        Example example = new Example(Order.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("orderStatus","2");
        criteria.andEqualTo("consignStatus","1");//可选,订单状态为已发货(2),那么收货状态肯定为已发货(1)
        criteria.andLessThanOrEqualTo("consignTime",localDate);
        //得到自动确认收货的订单
        List<Order> orderList = orderMapper.selectByExample(example);
        for (Order order : orderList) {
            System.out.println("过期订单 : "+order.getId() + " "+order.getConsignStatus());
            confirmTake(order.getId(),"system");//系统根据15天前的订单,进行自动确认收货
        }
    }

    public static void main(String[] args) {
        //计算出当前的订单的过期时间
        LocalDate now = LocalDate.now();
        LocalDate localDate = now.plusDays(-15);//15
        System.out.println(localDate);
    }

    /**
     * 构建查询对象
     * @param searchMap
     * @return
     */
    private Example createExample(Map<String, Object> searchMap){
        Example example=new Example(Order.class);
        Example.Criteria criteria = example.createCriteria();
        if(searchMap!=null){
            // 订单id
            if(searchMap.get("id")!=null && !"".equals(searchMap.get("id"))){
                criteria.andEqualTo("id",searchMap.get("id"));
           	}
            // 支付类型，1、在线支付、0 货到付款
            if(searchMap.get("payType")!=null && !"".equals(searchMap.get("payType"))){
                criteria.andEqualTo("payType",searchMap.get("payType"));
           	}
            // 物流名称
            if(searchMap.get("shippingName")!=null && !"".equals(searchMap.get("shippingName"))){
                criteria.andLike("shippingName","%"+searchMap.get("shippingName")+"%");
           	}
            // 物流单号
            if(searchMap.get("shippingCode")!=null && !"".equals(searchMap.get("shippingCode"))){
                criteria.andLike("shippingCode","%"+searchMap.get("shippingCode")+"%");
           	}
            // 用户名称
            if(searchMap.get("username")!=null && !"".equals(searchMap.get("username"))){
                criteria.andLike("username","%"+searchMap.get("username")+"%");
           	}
            // 买家留言
            if(searchMap.get("buyerMessage")!=null && !"".equals(searchMap.get("buyerMessage"))){
                criteria.andLike("buyerMessage","%"+searchMap.get("buyerMessage")+"%");
           	}
            // 是否评价
            if(searchMap.get("buyerRate")!=null && !"".equals(searchMap.get("buyerRate"))){
                criteria.andLike("buyerRate","%"+searchMap.get("buyerRate")+"%");
           	}
            // 收货人
            if(searchMap.get("receiverContact")!=null && !"".equals(searchMap.get("receiverContact"))){
                criteria.andLike("receiverContact","%"+searchMap.get("receiverContact")+"%");
           	}
            // 收货人手机
            if(searchMap.get("receiverMobile")!=null && !"".equals(searchMap.get("receiverMobile"))){
                criteria.andLike("receiverMobile","%"+searchMap.get("receiverMobile")+"%");
           	}
            // 收货人地址
            if(searchMap.get("receiverAddress")!=null && !"".equals(searchMap.get("receiverAddress"))){
                criteria.andLike("receiverAddress","%"+searchMap.get("receiverAddress")+"%");
           	}
            // 订单来源：1:web，2：app，3：微信公众号，4：微信小程序  5 H5手机页面
            if(searchMap.get("sourceType")!=null && !"".equals(searchMap.get("sourceType"))){
                criteria.andEqualTo("sourceType",searchMap.get("sourceType"));
           	}
            // 交易流水号
            if(searchMap.get("transactionId")!=null && !"".equals(searchMap.get("transactionId"))){
                criteria.andLike("transactionId","%"+searchMap.get("transactionId")+"%");
           	}
            // 订单状态
            if(searchMap.get("orderStatus")!=null && !"".equals(searchMap.get("orderStatus"))){
                criteria.andEqualTo("orderStatus",searchMap.get("orderStatus"));
           	}
            // 支付状态
            if(searchMap.get("payStatus")!=null && !"".equals(searchMap.get("payStatus"))){
                criteria.andEqualTo("payStatus",searchMap.get("payStatus"));
           	}
            // 发货状态
            if(searchMap.get("consignStatus")!=null && !"".equals(searchMap.get("consignStatus"))){
                criteria.andEqualTo("consignStatus",searchMap.get("consignStatus"));
           	}
            // 是否删除
            if(searchMap.get("isDelete")!=null && !"".equals(searchMap.get("isDelete"))){
                criteria.andEqualTo("isDelete",searchMap.get("isDelete"));
           	}

            // 数量合计
            if(searchMap.get("totalNum")!=null ){
                criteria.andEqualTo("totalNum",searchMap.get("totalNum"));
            }
            // 金额合计
            if(searchMap.get("totalMoney")!=null ){
                criteria.andEqualTo("totalMoney",searchMap.get("totalMoney"));
            }
            // 优惠金额
            if(searchMap.get("preMoney")!=null ){
                criteria.andEqualTo("preMoney",searchMap.get("preMoney"));
            }
            // 邮费
            if(searchMap.get("postFee")!=null ){
                criteria.andEqualTo("postFee",searchMap.get("postFee"));
            }
            // 实付金额
            if(searchMap.get("payMoney")!=null ){
                criteria.andEqualTo("payMoney",searchMap.get("payMoney"));
            }

        }
        return example;
    }

}
